package com.zenithmind.coding.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.context.UserContext;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.coding.mapper.ContestMapper;
import com.zenithmind.coding.pojo.dto.ContestCreateDTO;
import com.zenithmind.coding.pojo.entity.Contest;
import com.zenithmind.coding.pojo.vo.ContestVO;
import com.zenithmind.coding.service.ContestService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 编程竞赛服务实现类 - 遵循单一职责原则，专门处理竞赛相关功能
 * 
 * @author ZenithMind Team
 * @since 2025-01-09
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ContestServiceImpl extends ServiceImpl<ContestMapper, Contest> implements ContestService {

    private final ContestMapper contestMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContestVO createContest(ContestCreateDTO createDTO) {
        log.info("创建竞赛: title={}", createDTO.getTitle());
        
        Contest contest = new Contest();
        BeanUtils.copyProperties(createDTO, contest);
        
        // 设置创建者信息
        contest.setCreatorId(UserContext.getUserId());
        contest.setCreatorName(UserContext.getUsername());
        
        // 设置初始状态
        contest.setStatus(0); // 未开始
        contest.setCurrentParticipants(0);
        
        // 设置问题列表（JSON格式）
        if (createDTO.getProblemIds() != null && !createDTO.getProblemIds().isEmpty()) {
            contest.setProblemIds(String.join(",", createDTO.getProblemIds()));
        }
        
        if (!save(contest)) {
            throw new RuntimeException("创建竞赛失败");
        }
        
        log.info("创建竞赛成功: id={}", contest.getId());
        return convertToVO(contest);
    }

    @Override
    public PageResult<ContestVO> getContestPage(Long current, Long size, Integer status, Integer type, String keyword) {
        log.info("分页查询竞赛: current={}, size={}, status={}, type={}, keyword={}", 
                current, size, status, type, keyword);
        
        LambdaQueryWrapper<Contest> wrapper = new LambdaQueryWrapper<>();
        
        if (status != null) {
            wrapper.eq(Contest::getStatus, status);
        }
        if (type != null) {
            wrapper.eq(Contest::getType, type);
        }
        if (StringUtils.hasText(keyword)) {
            wrapper.like(Contest::getTitle, keyword)
                   .or()
                   .like(Contest::getDescription, keyword);
        }
        
        wrapper.orderByDesc(Contest::getCreateTime);
        
        IPage<Contest> page = new Page<>(current, size);
        IPage<Contest> result = page(page, wrapper);
        
        List<ContestVO> voList = result.getRecords().stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
        
        return PageResult.of(voList, result.getTotal(), current, size);
    }

    @Override
    public ContestVO getContestById(String id) {
        log.info("查询竞赛详情: id={}", id);
        Contest contest = getById(id);
        if (contest == null) {
            throw new RuntimeException("竞赛不存在");
        }
        return convertToVO(contest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ContestVO updateContest(String id, ContestCreateDTO updateDTO) {
        log.info("更新竞赛: id={}, title={}", id, updateDTO.getTitle());
        
        Contest contest = getById(id);
        if (contest == null) {
            throw new RuntimeException("竞赛不存在");
        }
        
        BeanUtils.copyProperties(updateDTO, contest);
        contest.setId(id);
        
        // 更新问题列表
        if (updateDTO.getProblemIds() != null && !updateDTO.getProblemIds().isEmpty()) {
            contest.setProblemIds(String.join(",", updateDTO.getProblemIds()));
        }
        
        if (!updateById(contest)) {
            throw new RuntimeException("更新竞赛失败");
        }
        
        log.info("更新竞赛成功: id={}", id);
        return convertToVO(contest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteContest(String id) {
        log.info("删除竞赛: id={}", id);
        
        Contest contest = getById(id);
        if (contest == null) {
            throw new RuntimeException("竞赛不存在");
        }
        
        // 检查竞赛状态，只能删除未开始的竞赛
        if (contest.getStatus() != 0) {
            throw new RuntimeException("只能删除未开始的竞赛");
        }
        
        boolean result = removeById(id);
        log.info("删除竞赛结果: id={}, result={}", id, result);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean joinContest(String contestId, String userId) {
        log.info("参加竞赛: contestId={}, userId={}", contestId, userId);
        
        // 检查是否已参加
        int count = contestMapper.checkUserParticipation(contestId, userId);
        if (count > 0) {
            throw new RuntimeException("已经参加了该竞赛");
        }
        
        // 检查竞赛状态和人数限制
        Contest contest = getById(contestId);
        if (contest == null) {
            throw new RuntimeException("竞赛不存在");
        }
        
        if (contest.getStatus() != 0) {
            throw new RuntimeException("竞赛已开始或已结束，无法参加");
        }
        
        if (contest.getMaxParticipants() != null && 
            contest.getCurrentParticipants() >= contest.getMaxParticipants()) {
            throw new RuntimeException("竞赛人数已满");
        }
        
        // 添加参与者
        int result = contestMapper.insertParticipant(contestId, userId);
        if (result > 0) {
            // 更新参与人数
            contest.setCurrentParticipants(contest.getCurrentParticipants() + 1);
            updateById(contest);
        }
        
        log.info("参加竞赛结果: contestId={}, userId={}, result={}", contestId, userId, result > 0);
        return result > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean leaveContest(String contestId, String userId) {
        log.info("退出竞赛: contestId={}, userId={}", contestId, userId);
        
        // 检查竞赛状态
        Contest contest = getById(contestId);
        if (contest == null) {
            throw new RuntimeException("竞赛不存在");
        }
        
        if (contest.getStatus() != 0) {
            throw new RuntimeException("竞赛已开始或已结束，无法退出");
        }
        
        // 移除参与者
        int result = contestMapper.deleteParticipant(contestId, userId);
        if (result > 0) {
            // 更新参与人数
            contest.setCurrentParticipants(Math.max(0, contest.getCurrentParticipants() - 1));
            updateById(contest);
        }
        
        log.info("退出竞赛结果: contestId={}, userId={}, result={}", contestId, userId, result > 0);
        return result > 0;
    }

    @Override
    public List<Object> getContestParticipants(String contestId, Integer limit) {
        log.info("获取竞赛参与者: contestId={}, limit={}", contestId, limit);
        return contestMapper.selectContestParticipants(contestId, limit);
    }

    @Override
    public List<Object> getContestLeaderboard(String contestId, Integer limit) {
        log.info("获取竞赛排行榜: contestId={}, limit={}", contestId, limit);
        return contestMapper.selectContestLeaderboard(contestId, limit);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean startContest(String contestId) {
        log.info("开始竞赛: contestId={}", contestId);
        
        Contest contest = getById(contestId);
        if (contest == null) {
            throw new RuntimeException("竞赛不存在");
        }
        
        if (contest.getStatus() != 0) {
            throw new RuntimeException("竞赛状态不正确");
        }
        
        // 检查开始时间
        if (contest.getStartTime().isAfter(LocalDateTime.now())) {
            throw new RuntimeException("竞赛开始时间未到");
        }
        
        int result = contestMapper.updateContestStatus(contestId, 1); // 进行中
        log.info("开始竞赛结果: contestId={}, result={}", contestId, result > 0);
        return result > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean endContest(String contestId) {
        log.info("结束竞赛: contestId={}", contestId);
        
        Contest contest = getById(contestId);
        if (contest == null) {
            throw new RuntimeException("竞赛不存在");
        }
        
        if (contest.getStatus() != 1) {
            throw new RuntimeException("竞赛未在进行中");
        }
        
        int result = contestMapper.updateContestStatus(contestId, 2); // 已结束
        log.info("结束竞赛结果: contestId={}, result={}", contestId, result > 0);
        return result > 0;
    }

    @Override
    public List<ContestVO> getUserContests(String userId, Integer limit) {
        log.info("获取用户参与的竞赛: userId={}, limit={}", userId, limit);
        List<Contest> contests = contestMapper.selectUserContests(userId, limit);
        return contests.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    public Boolean canUserJoinContest(String contestId, String userId) {
        log.info("检查用户是否可以参加竞赛: contestId={}, userId={}", contestId, userId);
        
        Contest contest = getById(contestId);
        if (contest == null) {
            return false;
        }
        
        // 检查竞赛状态
        if (contest.getStatus() != 0) {
            return false;
        }
        
        // 检查是否已参加
        int count = contestMapper.checkUserParticipation(contestId, userId);
        if (count > 0) {
            return false;
        }
        
        // 检查人数限制
        if (contest.getMaxParticipants() != null && 
            contest.getCurrentParticipants() >= contest.getMaxParticipants()) {
            return false;
        }
        
        return true;
    }

    @Override
    public Object getContestStatistics(String contestId) {
        log.info("获取竞赛统计: contestId={}", contestId);
        return contestMapper.selectContestStatistics(contestId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer batchImportContests(List<ContestCreateDTO> contests) {
        log.info("批量导入竞赛: size={}", contests.size());
        
        List<Contest> contestList = contests.stream()
                .map(dto -> {
                    Contest contest = new Contest();
                    BeanUtils.copyProperties(dto, contest);
                    contest.setCreatorId(UserContext.getUserId());
                    contest.setCreatorName(UserContext.getUsername());
                    contest.setStatus(0);
                    contest.setCurrentParticipants(0);
                    if (dto.getProblemIds() != null && !dto.getProblemIds().isEmpty()) {
                        contest.setProblemIds(String.join(",", dto.getProblemIds()));
                    }
                    return contest;
                })
                .collect(Collectors.toList());
        
        int result = contestMapper.batchInsertContests(contestList);
        log.info("批量导入竞赛结果: size={}, result={}", contests.size(), result);
        return result;
    }

    @Override
    public List<ContestVO> exportContests(List<String> contestIds) {
        log.info("导出竞赛: contestIds={}", contestIds);
        
        List<Contest> contests = listByIds(contestIds);
        return contests.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    /**
     * 转换为VO
     */
    private ContestVO convertToVO(Contest contest) {
        ContestVO vo = new ContestVO();
        BeanUtils.copyProperties(contest, vo);
        
        // 设置额外信息
        setAdditionalInfo(vo);
        
        return vo;
    }

    /**
     * 设置额外信息
     */
    private void setAdditionalInfo(ContestVO vo) {
        // 设置类型名称
        vo.setTypeName(getTypeName(vo.getType()));
        
        // 设置模式名称
        vo.setModeName(getModeName(vo.getMode()));
        
        // 设置状态名称
        vo.setStatusName(getStatusName(vo.getStatus()));
        
        // 计算剩余时间
        if (vo.getEndTime() != null && vo.getStatus() == 1) {
            long remainingMinutes = java.time.Duration.between(LocalDateTime.now(), vo.getEndTime()).toMinutes();
            vo.setRemainingTime(Math.max(0, remainingMinutes));
        }
        
        // 设置是否可以参加
        String currentUserId = UserContext.getUserId();
        if (currentUserId != null) {
            vo.setCanJoin(canUserJoinContest(vo.getId(), currentUserId));
            vo.setUserJoined(contestMapper.checkUserParticipation(vo.getId(), currentUserId) > 0);
        }
    }

    /**
     * 获取类型名称
     */
    private String getTypeName(Integer type) {
        if (type == null) return "未知";
        return switch (type) {
            case 1 -> "个人赛";
            case 2 -> "团队赛";
            case 3 -> "练习赛";
            case 4 -> "正式赛";
            default -> "未知";
        };
    }

    /**
     * 获取模式名称
     */
    private String getModeName(Integer mode) {
        if (mode == null) return "未知";
        return switch (mode) {
            case 1 -> "ACM模式";
            case 2 -> "OI模式";
            case 3 -> "IOI模式";
            default -> "未知";
        };
    }

    /**
     * 获取状态名称
     */
    private String getStatusName(Integer status) {
        if (status == null) return "未知";
        return switch (status) {
            case 0 -> "未开始";
            case 1 -> "进行中";
            case 2 -> "已结束";
            case 3 -> "已取消";
            default -> "未知";
        };
    }
}
